#!/usr/bin/ruby
# encoding: utf-8
# -*- coding: utf-8 -*-
# vim:set fileencoding=utf-8:

#bilibilidownloader/video.rb
require_relative "config.rb"
require "http" # need "http" module:https://github.com/httprb/http
require "json" 
require "digest"
require "stringio"
#require "open-uri" #Have no need
require "gzip" # need "gzip" module:http://jockofcode.com/gzip
#require "streamio-ffmpeg" #Plan to add
module BilibiliDownloader
  module Video
    def downloadVideo(videoList,aid)
      result = Array.new
      uri = "https://api.bilibili.com/x/web-interface/view?aid=#{aid}"
      headers = {"User-Agent"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0","Accept"=>"*/*","Accept-Language"=>"en-US,en;q=0.5","Accept-Encoding"=>"gzip, deflate, br","Range"=>"bytes=0-","Referer"=>uri,"Origin"=>'https://www.bilibili.com','Connection'=>'keep-alive'}
      if videoList.is_a?(Array) == false then
        result.push(StringIO.new(HTTP.headers(headers).get(videoList.to_s)))
      elsif videoList.length == 1 then
        result.push(StringIO.new(HTTP.headers(headers).get(videoList[0]).to_s))
      else
	thread = Array.new
	thresult = Hash.new
	videoList.each_with_index do |item,index|
	  thread << Thread.new do
	    thresult.store(index,StringIO.new(HTTP.headers(headers).get(item).to_s))
	  end
	end
        thread.each do |thr| 
          thr.join
        end
	thresult.keys.sort.each do |i|
	  result.push(thresult[i])
	end
      end
      return result
    end
    def getVideo(aid,cid,quality,sessdata)
      url = "https://api.bilibili.com/x/player/playurl?cid=#{cid}&avid=#{aid}&qn=#{quality}"
      headers = {"User-Agent"=>"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36","Cookie"=>"SESSDATA=#{sessdata}","Host"=>"api.bilibili.com"}
      html = JSON.parse(HTTP.headers(headers).get(url).to_s)
      result = Array.new
      html["data"]["durl"].each do |item|
	result.push(item["url"])
      end
      return result
    end
    #此api无法用于番剧视频
    def getVideoPrivate(aid,cid,quality)
      entropy = 'rbMCKn@KuamXWlPMoJGsKcbiJKUfkPF_8dABscJntvqhRSETg'
      appkey,sec = entropy.reverse.split(//).map{|i| (i.ord+2).chr }.join.split(/\:/)
      uri = "https://api.bilibili.com/x/web-interface/view?aid=#{aid}"
      params = "appkey=#{appkey}&cid=#{cid}&otype=json&qn=#{quality}&quality=#{quality}&type="
      chksum = Digest::MD5.hexdigest(params.encode("UTF-8") + sec.encode("UTF-8"))
      url = "https://interface.bilibili.com/v2/playurl?#{params}&sign=#{chksum}"
      headers = {"Referer"=>uri,"User-Agent"=>"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"}
      html = JSON.parse(HTTP.headers(headers).get(url).to_s)
      result = Array.new
      html["durl"].each do |item|
	result.push(item["url"])
      end
      return result
    end
    def getVideoInfo(aid,p=nil,onlycid = false)
      headers = {"User-Agent"=>"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"}
      html = JSON.parse(HTTP.headers(headers).get("https://api.bilibili.com/x/web-interface/view?aid=#{aid}").to_s)
      data = html['data']
      result = Hash.new
      result.store("title",data["title"])
      videoList = Array.new
      if p.nil? == false then
	if p.is_a?(Array) then
	  p.each do |item|
	    videoList.push(data["pages"][item.to_i-1])
	  end
	else
	  videoList.push(data["pages"][p.to_i-1])
	end
      else
	videoList = data["pages"].dup
      end
      result.store("videoList",videoList.dup)
      return (onlycid ? result["videoList"].map {|item| item["cid"] } : result)
    end
    def getBangumiInfo(ep)
      uri = "https://www.bilibili.com/bangumi/play/ep#{ep}"
      headers = {"User-Agent"=>"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"}
      html = HTTP.headers(headers).get(uri).to_s.gunzip
      if /INITIAL_STATE__=(.*?"\]});/ =~ html then
	info = JSON.parse(Regexp.last_match[1])
	result = {"name"=>info["mediaInfo"]["title"],"videoList"=>info["epList"].map {|i| {"aid"=>i["aid"],"cid"=>i["cid"],"title"=>i["title"],"longTitle"=>i["longTitle"]}}}
      else
	return nil
      end
      return result
    end
    module_function :downloadVideo,:getVideo,:getVideoInfo,:getVideoPrivate,:getBangumiInfo
  end
end

